package com.alogic.blob.resource;

import com.alogic.blob.BlobInfo;
import com.alogic.blob.BlobManager;
import com.alogic.blob.BlobReader;
import com.alogic.blob.BlobWriter;
import com.anysoft.util.*;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Element;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 基于只读本地文件系统的资源
 *
 * @since 1.6.13.19 [20201014 duanyy]
 */
public class ReadonlyFileSystem extends BlobManager.Abstract{

    /**
     * 从路径中匹配id的正则表达式
     */
    protected static final Pattern idPattern = Pattern.compile("([^<>|:\"\"\\*\\?]+)\\.\\w+$");

    /**
     * 路径
     */
    protected String home = "";

    /**
     * content type
     */
    protected String contentType = "text/plain";

    /**
     * 文件后缀
     */
    protected String suffix=".xml";

    /**
     * 信息集
     */
    protected Map<String, ResourceBlobInfo> infos = new ConcurrentHashMap<String,ResourceBlobInfo>();

    /**
     * 获取根路径
     * @return home
     */
    public String getHome(){return home;}

    /**
     * 获取content-type
     * @return content-type
     */
    public String getContentType(){return contentType;}

    @Override
    public BlobWriter newFile(String id) {
        throw new BaseException("core.e1000","This function is not suppurted yet.");
    }

    @Override
    public BlobReader getFile(String id) {
        ResourceBlobInfo info = infos.get(id);
        return info == null ? null : new ResourceBlobReader(info);
    }

    @Override
    public boolean existFile(String id) {
        return infos.containsKey(id);
    }

    @Override
    public boolean deleteFile(String id) {
        throw new BaseException("core.e1000","This function is not suppurted yet.");
    }

    @Override
    public void report(Element xml) {
        if (xml != null){
            super.report(xml);
            XmlTools.setString(xml, "home", this.getHome());
            XmlTools.setString(xml, "contentType", this.getContentType());
        }
    }

    @Override
    public void report(Map<String, Object> json) {
        if (json != null){
            super.report(json);
            JsonTools.setString(json, "home", this.getHome());
            JsonTools.setString(json, "contentType", this.getContentType());
        }
    }

    @Override
    public void configure(Properties p) {
        super.configure(p);

        contentType = PropertiesConstants.getString(p,"contentType",contentType,true); // NOSONAR
        suffix = PropertiesConstants.getString(p,"suffix",suffix);
        home = PropertiesConstants.getString(p,"home","",true);

        scanResource(home);
    }

    protected void scanResource(String pHome) {
        if (StringUtils.isNotEmpty(pHome)){
            File file = new File(pHome);
            scanFileSystem(pHome,file);
        }else{
            LOG.warn("The home path is null");
        }
    }

    protected void scanFileSystem(String pHome, File pFile){
        File[] files = pFile.listFiles();
        for (File item:files){
            if (item.isDirectory()){
                scanFileSystem(pHome + "/" + item.getName(),item);
            }else {
                if (item.getName().endsWith(this.suffix)) {
                    resourceFound(pHome + "/" + item.getName());
                }
            }
        }
    }

    /**
     * 发现资源
     * @param path 路径
     */
    protected void resourceFound(String path) {
        Matcher m = idPattern.matcher(path);
        if (m.find()){
            String id = m.group(1);
            if (StringUtils.isNotEmpty(id)){
                String shortId = id.substring(home.length());
                if (StringUtils.isNotEmpty(shortId)) {
                    resourceFound(shortId, new ResourceBlobInfo(shortId, path, getContentType()));
                }
            }
        }
    }

    /**
     * 发现可用资源
     * @param id 资源id
     * @param info BlobInfo
     */
    protected void resourceFound(String id,ResourceBlobInfo info){
        infos.put(id,info);
    }

    /**
     * BlobInfo
     * @author yyduan
     *
     */
    public static class ResourceBlobInfo extends BlobInfo.Abstract{
        protected String path;
        public ResourceBlobInfo(String id,String path,String contentType) {
            super(id,contentType);
            this.path = path;
        }

        public String getPath(){
            return path;
        }
    }

    /**
     * Reader
     * @author yyduan
     *
     */
    public static class ResourceBlobReader implements BlobReader {

        /**
         * blob info
         */
        protected ResourceBlobInfo info;

        public ResourceBlobReader(ResourceBlobInfo info){
            this.info = info;
        }

        @Override
        public InputStream getInputStream(long offset) {
            String path = info.getPath();
            try {
                return new FileInputStream(new File(path));
            } catch (FileNotFoundException e) {
                LOG.error("Can not find file:" + path);
                return null;
            }
        }

        @Override
        public void finishRead(InputStream in) {
            IOTools.close(in);
        }

        @Override
        public BlobInfo getBlobInfo() {
            return info;
        }

    }
}
